perm filename GOBBLE.SAI[AL,HE]1 blob sn#290121 filedate 1977-06-28 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00018 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	IFCR ¬DECLARATION(EXTENDED_COMPILATION) THENC
C00004 00003	SIMPLE INTEGER PROCEDURE STINDX(STRING SINTEGER CH)
C00005 00004	CHANNEL STUFF:  readfile, writefile
C00007 00005	!  Definitions
C00009 00006	!  rwdo, rwmake, dirmake, codemake, dtypmake, inpinit
C00016 00007	!  nextline, inscan, skipblanks, scan_token
C00020 00008	!  read and fread
C00023 00009	!  get_dtype, verify_dtype, verify_1, verify_2, verify_3, dtype_check
C00030 00010	!  asgbki, identlookup, vblmake, vtry, mkblkbody
C00036 00011	!  grovel (lllop, gllop, widget, stgrovel, lgrovel, constelim)
C00040 00012	!  grovel: REGROVEL:  DIR, EOP, DTYP
C00045 00013	!  grovel: main body:   PROG,BLOCK,COBLOCK,FORR,WHIL,IFF,PAUSE,ABORT,CIF,COMMNT
C00049 00014	!  grovel: main body:   NOMV, BINDV, DBD, NW, PVL, ASSERT, DENY, AFACT, SFACT
C00052 00015	!  grovel: main body:   AFFIX, UNFIX, GASSIGN, CALCULATOR, CHANGER, ALSODO, SPECVAL
C00055 00016	!  grovel: main body:   V3ECT, TRANS, ASSIGNMENT, EVDO, PRNT
C00059 00017	!  grovel: main body:   MOVE$, OPERATE, CENTER, STOP, motion clauses
C00067 00018	! MAIN PROGRAM
C00068 ENDMK
C⊗;
IFCR ¬DECLARATION(EXTENDED_COMPILATION) THENC

	ENTRY;

BEGIN  "GOBBLE"
IFCR ¬DECLARATION(CREFFING) THENC DEFINE CREFFING="FALSE"; ENDC
IFCR ¬ CREFFING THENC
REQUIRE "ALREQ.HDR[AL,HE]" SOURCE_FILE;
ENDC
REDEFINE $$PRGID "[]" = ["GOBBLE"];
ENDC

REQUIRE 1500 NEW_ITEMS;

RCLASS RESERVED_WORD(ITEMVAR RWSYM;INTEGER RWTYPE;INTEGER CODE);
!  RCLASS STCONST(STRING ITEMVAR VAL).  This is now in ALREC.  RF 3/23/76;
RCLASS IVAR(ITEMVAR IVAR);

DEFINE DSKIN_OP = 1;
DEFINE INIOUT_OP = 2;

SIMPLE INTEGER PROCEDURE STINDX(STRING S;INTEGER CH);
	START_CODE
	LABEL XIT,LP;
	DEFINE SP='16;
	MOVEI	1,0;
	HRRZ	2,-1(SP);
	JUMPE	2,XIT;
	MOVE	3,(SP);
	MOVE	4,CH;
LP:	ADDI	1,1;
	ILDB	5,3;
	CAMN	5,4;
	JRST	XIT;
	SOJG	2,LP;
	MOVEI	1,0;
XIT:	END;
COMMENT CHANNEL STUFF:  readfile, writefile;
DEFINE MAXFILES="15";
STRING ARRAY FID[0:MAXFILES];
INTEGER ARRAY EOF[0:MAXFILES];
INTEGER ARRAY BRCHAR[0:MAXFILES];


INTEGER PROCEDURE READFILE(STRING FILEID;INTEGER DMODE(0));
	BEGIN
	INTEGER CH;
	CH←GETCHAN;
	FID[CH]←FILEID;
	OPEN(CH,"DSK",DMODE,3,0,512,BRCHAR[CH],EOF[CH]);
	LOOKUP(CH,FILEID,EOF[CH]);
	IF EOF[CH] THEN 
		BEGIN
		USERERR(1,1,"LOOKUP FAILED FOR |"&FILEID&"|");
		RELEASE(CH);
		CH←-1;
		END;
	RETURN(CH);
	END;

INTEGER PROCEDURE WRITEFILE(STRING FILEID;INTEGER DMODE(0));
	BEGIN
	INTEGER CH;
	CH←GETCHAN;
	CH←GETCHAN;
	FID[CH]←FILEID;
	OPEN(CH,"DSK",DMODE,0,3,512,BRCHAR[CH],EOF[CH]);
	ENTER(CH,FILEID,EOF[CH]);
	IF EOF[CH] THEN 
		BEGIN
		USERERR(1,1,"ENTER FAILED FOR |"&FILEID&"|");
		RELEASE(CH);
		CH←-1;
		END;
	RETURN(CH);
	END;

RCLASS CHAR_REC(INTEGER CHAR);
!  Definitions;

DEFINE MAXINPLEV=3;
INTEGER ARRAY SCNCHN[1:MAXINPLEV];
STRING ARRAY SCNSTK[0:MAXINPLEV];
INTEGER INPLEV;

RANY ITEMVAR SYM;
STRING SCNID;
REAL SCNRVAL;
INTEGER SCNIVAL;


INTEGER LINBRK,BLNKBRK,IDBRK,STRBRK;

DEFINE	UNKN_CODE = 0;		! Unknown code;
DEFINE	IDENT_CODE = -1;	! identifier;
DEFINE	VAR_CODE = -2;		! Declared variable **** NOT USED ANY MORE ***;
DEFINE	RW_CODE = -3;		! Reserved word;
DEFINE	VAL_CODE = -4;		! Scalar value;
DEFINE	STR_CODE = -5;		! String constant;
DEFINE	DIR_CODE = -6;		! Directive (DSKIN, INIOUT);
DEFINE	EOP_CODE = -7;		! Expression operation (SADD ...);
DEFINE	DTYP_CODE = -8;		! Declaration (SVAR ...);
DEFINE	IV_CODE = -9;		! Itemvar;
DEFINE	CONST_CODE = -10;	! Predeclared constant (NILVECT ...);
!  rwdo, rwmake, dirmake, codemake, dtypmake, inpinit;

DEFINE GVAL_DTYPE = "0";

PROCEDURE RWDO(STRING ID;INTEGER TYPE,I);
	BEGIN
	RANY ITEMVAR V;
	V←NEW(NEW_RECORD(RESERVED_WORD));
	RESERVED_WORD:RWTYPE[∂(V)]←TYPE;
	RESERVED_WORD:CODE[∂(V)]←I;
	RESERVED_WORD:RWSYM[∂(V)]←V;
	NEW_PNAME(V,ID);
	END;

PROCEDURE RWMAKE(STRING ID;INTEGER I);
	RWDO(ID,RW_CODE,I);

PROCEDURE DIRMAKE(STRING ID;INTEGER I);
	RWDO(ID,DIR_CODE,I);

PROCEDURE CODEMAKE(STRING ID;INTEGER I);
	RWDO(ID,EOP_CODE,I);

PROCEDURE DTYPMAKE(STRING ID;INTEGER I);
	RWDO(ID,DTYP_CODE,I);

PROCEDURE INPINIT;

	BEGIN
	SETBREAK(LINBRK←GETBREAK,LF,CR,"INS"); ! line break;
	SETBREAK(BLNKBRK←GETBREAK," "&FF&TAB&CR&LF,NULL,"XRN");
	SETBREAK(IDBRK←GETBREAK,"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_",NULL,"KXRN");
	SETBREAK(STRBRK←GETBREAK,""""&LF,CR,"INS");
	INPLEV←0;
	DIRMAKE("DSKIN",DSKIN_OP);
	RWMAKE("NULL",0);
	RWMAKE("AFFIX",AFFIXTYPE);
	RWMAKE("COMMENT",COMMNTTYPE);  ! Added by RF;
	RWMAKE("ALSO",ALSODOTYPE);  !  Added by RF;
	RWMAKE("SPEC",SPECVALTYPE);  ! Added by RF.  NEWV and OLDV;
	RWMAKE("ON",CMONTYPE);  ! Added by RF;
	RWMAKE("EV",EVDOTYPE);  ! Added by RF;
	RWMAKE("CMABLE",CMABLETYPE);
	RWMAKE("UNFIX",UNFIXTYPE);
	RWMAKE("PR",PROGTYPE);
	RWMAKE("CLC",CALCULATORTYPE);
	RWMAKE("CHG",CHANGERTYPE);
	RWMAKE("BL",BLOCKTYPE);
	RWMAKE("CO",COBLOCKTYPE);
	RWMAKE("FO",FORRTYPE);
	RWMAKE("WH",WHILTYPE);
	RWMAKE("IF",IFFTYPE);
	RWMAKE("PAUSE",PAUSETYPE);
	RWMAKE("ABORT",ABORTTYPE);
	RWMAKE("AS",ASSIGNMENTTYPE);
	RWMAKE("CIF",CIFTYPE);
	RWMAKE("PAS",PASTYPE);	! Added by arg - translates to an arith assert;
	RWMAKE("ASSERT",ASSERTTYPE);
	RWMAKE("DENY",DENYTYPE);
	RWMAKE("AF",AFACTTYPE);
	RWMAKE("SF",SFACTTYPE);
	RWMAKE("MO",MOVE$TYPE);
	RWMAKE("OPERATE",OPERATETYPE);
	RWMAKE("CENTER",CENTERTYPE);  ! Added by RF;
	RWMAKE("STOP",STOPTYPE);  ! Added by RF;
	RWMAKE("DURATION",DURATIONTYPE);  ! Added by RF;
	RWMAKE("FORCE",FORCETYPE);
	RWMAKE("FORCE_FRAME",F_FRAMETYPE);
	RWMAKE("PRINT",PRNTTYPE);  ! Added by RF;
	RWMAKE("VIA",VIATYPE);	! Added by RF;
	RWMAKE("VELOCITY",VELOCITYTYPE);  ! Added by ARG;
	RWMAKE("ARRIVAL",ARRIVALTYPE);  ! Added by ARG;
	RWMAKE("DEPARTURE",DEPARTURETYPE);  ! Added by ARG;
	RWMAKE("OPENING",OPENINGTYPE);  ! Added by ARG;
	RWMAKE("WOBBLE",WOBBLETYPE);  ! Added by ARG;
	RWMAKE("SPEED_FACTOR",S_FACTYPE);  ! Added by ARG;
	RWMAKE("EX",EXPRNTYPE);
	RWMAKE("VA",VARIABLETYPE);
	RWMAKE("SC",SVALTYPE);
	RWMAKE("PVL",PVLTYPE);
	RWMAKE("NW",NWTYPE);
	RWMAKE("DBD",DBDTYPE);
	RWMAKE("NOTE",NOTETYPE);   ! Added by ARG - for debugging;
	RWMAKE("NOTE1",NOTE1TYPE);
	RWMAKE("NOTE2",NOTE2TYPE);
	RWMAKE("GAS",GASSIGNTYPE);
	RWMAKE("NOMV",NOMVTYPE);
	RWMAKE("BIND",BINDVTYPE);
	CODEMAKE("NOOP",NO_OP);
	CODEMAKE("SADD",SADD_OP);
	CODEMAKE("SSUB",SSUB_OP);
	CODEMAKE("SMUL",SMUL_OP);
	CODEMAKE("SNEG",SNEG_OP);
	CODEMAKE("SDIV",SDIV_OP);
	CODEMAKE("SLT",SLT_OP);
	CODEMAKE("SEQ",SEQ_OP);
	CODEMAKE("SLE",SLE_OP);
	CODEMAKE("SGE",SGE_OP);
	CODEMAKE("SNE",SNE_OP);
	CODEMAKE("SGT",SGT_OP);
	CODEMAKE("AND",AND_OP);
	CODEMAKE("OR",OR_OP);
	CODEMAKE("NOT",NOT_OP);
	CODEMAKE("VMAGN",VMAGN_OP);
	CODEMAKE("VDOT",VDOT_OP);
	CODEMAKE("VMAKE",VMAKE_OP);
	CODEMAKE("SVMUL",SVMUL_OP);
	CODEMAKE("VADD",VADD_OP);
	CODEMAKE("VSUB",VSUB_OP);
	CODEMAKE("RVMUL",RVMUL_OP);
	CODEMAKE("TVMUL",TVMUL_OP);
	CODEMAKE("AXIS",AXIS_OP);
	CODEMAKE("RMAGN",RMAGN_OP);
	CODEMAKE("UVECT",UVECT_OP);
	CODEMAKE("POS",POS_OP);
	CODEMAKE("ORIENT",ORIENT_OP);
	CODEMAKE("RRMUL",RRMUL_OP);
	CODEMAKE("AXW_ROTN",AXW_ROTN_OP);
	CODEMAKE("TMAKE",TMAKE_OP);
	CODEMAKE("FTOF",FTOF_OP);
	CODEMAKE("TVADD",TVADD_OP);
	CODEMAKE("TVSUB",TVSUB_OP);
	CODEMAKE("TTMUL",TTMUL_OP);
	CODEMAKE("TINVRT",TINVRT_OP);
	CODEMAKE("DEPR",DEPR_OP);  ! Added by ARG;
	CODEMAKE("FMAKE",FMAKE_OP);
	DTYPMAKE("GVAR",GVAL_DTYPE); ! Global.  Added by RF;
	DTYPMAKE("SVAR",SVAL_DTYPE);
	DTYPMAKE("VVAR",V3ECT_DTYPE);
	DTYPMAKE("TVAR",TRANS_DTYPE);
	DTYPMAKE("RVAR",ROTN_DTYPE);
	DTYPMAKE("FVAR",FRAME_DTYPE);
	DTYPMAKE("ATOM",ATOM_DTYPE);
	DTYPMAKE("EVAR",EVENT_DTYPE);
	DTYPMAKE("WVAR",WORLD_DTYPE);

	DTYPMAKE("CLCLAB",CLCLAB_DTYPE);
	DTYPMAKE("CHGLAB",CHGLAB_DTYPE);
	DTYPMAKE("OMNLAB",OMNLAB_DTYPE);
	DTYPMAKE("STMLAB",STMLAB_DTYPE);

	END;

REQUIRE INPINIT INITIALIZATION;
!  nextline, inscan, skipblanks, scan_token;

PROCEDURE NEXTLINE;
	BEGIN
	WHILE INPLEV>0 DO
		BEGIN
		IF ¬EOF[SCNCHN[INPLEV]] THEN
			BEGIN
			SCNSTK[INPLEV]←SCNSTK[INPLEV]&
				INPUT(SCNCHN[INPLEV],LINBRK);
			RETURN;
			END
		ELSE
			BEGIN
			RELEASE(SCNCHN[INPLEV]);
			INPLEV←INPLEV-1;
			END;
		END;
	OUTSTR("*");
	SCNSTK[0]←SCNSTK[0]&INCHWL&LF;
	END;

STRING PROCEDURE INSCAN(INTEGER BRKTBL;REFERENCE INTEGER BC);
	BEGIN
	WHILE ¬LENGTH(SCNSTK[INPLEV]) DO NEXTLINE;
	RETURN(SCAN(SCNSTK[INPLEV],BRKTBL,BC));
	END;

INTEGER PROCEDURE SKIPBLANKS;
	BEGIN
	! returns the first non-"blank" character;
	INTEGER C;
	STRING S;
	DO S←INSCAN(BLNKBRK,C) UNTIL C≠0;
	RETURN(C);
	END;

INTEGER PROCEDURE SCAN_TOKEN;
	BEGIN
	INTEGER C,IX;
	C←SKIPBLANKS; 
	IF "A" ≤(C LAND '137)≤ "Z" ∨ C="_" THEN
		BEGIN  ! Modified by RF;
		! an identifier;
		INTEGER TYP;
		SCNID←INSCAN(IDBRK,C);
		SYM←CVSI(SCNID,C);
		IF C THEN
			RETURN(IDENT_CODE)
		ELSE IF TYPEIT(SYM)≠REC_CODE THEN
			RETURN(IV_CODE);
		TYP ← RECTYPE(∂(SYM));
		IF TYP=LOC(RESERVED_WORD) THEN
			RETURN(RESERVED_WORD:RWTYPE[∂(SYM)])
		ELSE IF TYP=LOC(IDENT) THEN
			RETURN(IDENT_CODE)
		ELSE IF TYP=LOC(VARIABLE) THEN
			RETURN(VAR_CODE)
		ELSE IF TYP=LOC(SVAL) ∨ TYP=LOC(V3ECT) ∨ TYP=LOC(ROTN) ∨
		    TYP=LOC(FRAME) ∨ TYP=LOC(TRANS) THEN
			RETURN(CONST_CODE)
		ELSE 
			RETURN(IV_CODE);
		END;
	IX←IF C="-" ∨ C="+" THEN 2 ELSE 1;
	IF SCNSTK[INPLEV][IX FOR 1]="." THEN IX←IX+1;
	IF "0"≤SCNSTK[INPLEV][IX FOR 1]≤"9" THEN
		BEGIN
		SCNRVAL←REALSCAN(SCNSTK[INPLEV],C);
		RETURN(VAL_CODE);
		END;
	IF C="""" THEN
		BEGIN
		SCNID←NULL;
		WHILE TRUE DO
			BEGIN
			C←LOP(SCNSTK[INPLEV]);
			SCNID←SCNID&INSCAN(STRBRK,C);
			IF C="""" THEN
				BEGIN
				IF SCNSTK[INPLEV]="""" THEN
					SCNID←SCNID&LOP(SCNSTK[INPLEV])
				ELSE DONE;
				END
			ELSE IF C=LF ∨ C=0 THEN
				SCNID ← SCNID & CRLF;
			END;
		IF SCNID = NULL THEN SCNID ← CRLF; 
		RETURN(STR_CODE);
		END;

	C←SCNID←LOP(SCNSTK[INPLEV]);
	RETURN(C);
	END;
!  read and fread;

INTERNAL RANY RECURSIVE PROCEDURE READ(INTEGER T(0));
	BEGIN
	RCELL LD;
	RCELL C;
	RANY V;
	LABEL RESCANNIT;

RESCANNIT:
	IF T=0 THEN
		T←SCAN_TOKEN;

	IF T≤0 THEN
		CASE -T OF 
			BEGIN

	[-IDENT_CODE] 	BEGIN
			SYM←CVSI(SCNID,T);
			IF ¬T THEN RETURN(∂(SYM));
			SYM←NEW(NEW_RECORD(IDENT));
			IDENT:ID[∂(SYM)]←SYM;
			NEW_PNAME(SYM,SCNID);
			RETURN(∂(SYM));
			END;

	[-RW_CODE]	RETURN(∂(SYM));

	[-DIR_CODE]	RETURN(∂(SYM));

	[-EOP_CODE]	RETURN(∂(SYM));

	[-DTYP_CODE]	RETURN(∂(SYM));

	[-VAR_CODE]	RETURN(∂(SYM));

	[-CONST_CODE]	RETURN(∂(SYM));  ! Added by RF;

	[-VAL_CODE]	BEGIN
			V←NEW_RECORD(SVAL);
			SVAL:VAL[V]←SCNRVAL;
			RETURN(V);
			END;

	[-STR_CODE]	BEGIN
			V←NEW_RECORD(STCONST);
			STCONST:VAL[V]←NEW(SCNID);
			RETURN(V);
			END;

	[-IV_CODE]	BEGIN
			V←NEW_RECORD(IVAR);
			IVAR:IVAR[V]←SYM;
			RETURN(V);
			END;

	[UNKN_CODE]	BEGIN
			USERERR(1,1,"CONFUSION IN THE SCANNER");
			RETURN(NULL_RECORD);
			END

			END;

	IF T="(" THEN
		BEGIN
		LD←C←NULL_RECORD;
		WHILE (T←SCAN_TOKEN)≠")" DO
			BEGIN
			V←CONS(READ(T),NULL_RECORD);
			IF LD=NULL_RECORD THEN
				LD←V
			ELSE
				CELL:CDR[C]←V;
			C←V;
			END;
		RETURN(LD);
		END
	ELSE
		BEGIN
		V←NEW_RECORD(CHAR_REC);
		CHAR_REC:CHAR[V]←T;
		RETURN(V);
		END;
	END;

INTERNAL RANY RECURSIVE PROCEDURE FREAD(STRING FILE_NAME);
BEGIN	! hack for linking with the parser and/or snail in rpg mode;
    SCNSTK[0]←"(DSKIN """&FILE_NAME&""") ";
    RETURN(READ)
END;
!  get_dtype, verify_dtype, verify_1, verify_2, verify_3, dtype_check;

FORWARD RPTR(VARIABLE) PROCEDURE VTRY
    (RANY V;INTEGER DTYP (INVALID_DTYPE));
    ! On the next page;

INTEGER PROCEDURE GET_DTYPE(RPTR(EXPRN,VARIABLE,VALU$,CALCULATOR,LBLVAR) X;
					    INTEGER DTYP (INVALID_DTYPE));
	BEGIN
	!  Modified by RF.  If X is a variable, VTRY is called
	on it with DTYP.  This helps in properly declaring
	undeclared variables which are first used in expressions;
	INTEGER I;
	I←RECTYPE(X);
	RETURN(IF I=LOC(EXPRN) THEN EXPRN:DATATYPE[X]
		ELSE IF I=LOC(LBLVAR) THEN LBLVAR:DATATYPE[X]
		ELSE IF I=LOC(CALCULATOR) THEN GET_DTYPE(CALCULATOR:FORM[X])
		ELSE IF I=LOC(VARIABLE) THEN 
		    VARIABLE:DATATYPE[VTRY(X,DTYP)]
		ELSE IF I=LOC(SVAL) THEN SVAL_DTYPE
		ELSE IF I=LOC(V3ECT) THEN V3ECT_DTYPE
		ELSE IF I=LOC(ROTN) THEN ROTN_DTYPE
		ELSE IF I=LOC(TRANS) THEN TRANS_DTYPE
		ELSE IF I=LOC(FRAME) THEN FRAME_DTYPE
		ELSE INVALID_DTYPE);
	END;


PROCEDURE VERIFY_DTYPE(RPTR(EXPRN,VARIABLE,VALU$) X;INTEGER T);
	BEGIN
	INTEGER TT;
	TT←GET_DTYPE(X,T);
	IF TT≠T THEN
		BEGIN
		IF ¬(TT=FRAME_DTYPE∧T=TRANS_DTYPE) THEN
                    BEGIN
                    ALPRIN(X);
                    USERERR(1,1,"PARSER: wrong expression data type");
                    END;
		END;
	END;

PROCEDURE VERIFY_1(RCELL C;INTEGER T);
	BEGIN
	IF C=NULL THEN
		BEGIN
		USERERR(1,1,"NOT ENOUGH ARGS");
		END
	ELSE
		VERIFY_DTYPE(CELL:CAR[C],T);
	END;

PROCEDURE VERIFY_2(RCELL C;INTEGER T1,T2);
	BEGIN
	IF CL_LEN(C)<2 THEN
		BEGIN
		USERERR(1,1,"NOT ENOUGH ARGS");
		END
	ELSE
		BEGIN
		VERIFY_DTYPE(CELL:CAR[C],T1);
		VERIFY_DTYPE(CELL:CAR[CELL:CDR[C]],T2);
		END;
	END;

PROCEDURE VERIFY_3(RCELL C;INTEGER T1,T2,T3);
	BEGIN
	IF C=NULL THEN
		USERERR(1,1,"NOT ENOUGH ARGS")
	ELSE
		BEGIN
		VERIFY_DTYPE(CELL:CAR[C],T1);
		VERIFY_2(CELL:CDR[C],T2,T3);
		END;
	END;

PROCEDURE DTYPE_CHECK(RPTR(EXPRN) E);
	BEGIN
	INTEGER OP;
	RCELL EARGS;

	OP←EXPRN:OP[E];
	EARGS←EXPRN:ARGS[E];

	EXPRN:DATATYPE[E]←
		IF MIN_SVAL_OP≤OP≤MAX_SVAL_OP THEN SVAL_DTYPE
		ELSE IF MIN_V3ECT_OP≤OP≤MAX_V3ECT_OP THEN V3ECT_DTYPE
		ELSE IF MIN_ROTN_OP≤OP≤MAX_ROTN_OP THEN ROTN_DTYPE
		ELSE IF MIN_TRANS_OP≤OP≤MAX_TRANS_OP THEN TRANS_DTYPE
		ELSE IF MIN_FRAME_OP≤OP≤MAX_FRAME_OP THEN FRAME_DTYPE
		ELSE INVALID_DTYPE;

	CASE OP OF
		BEGIN

[SADD_OP]	VERIFY_2(EARGS,SVAL_DTYPE,SVAL_DTYPE);
[SSUB_OP]	VERIFY_2(EARGS,SVAL_DTYPE,SVAL_DTYPE);
[SNEG_OP]	VERIFY_1(EARGS,SVAL_DTYPE);
[SMUL_OP]	VERIFY_2(EARGS,SVAL_DTYPE,SVAL_DTYPE);
[SDIV_OP]	VERIFY_2(EARGS,SVAL_DTYPE,SVAL_DTYPE);
[SLT_OP]	VERIFY_1(EARGS,SVAL_DTYPE);
[SGT_OP]	VERIFY_1(EARGS,SVAL_DTYPE);
[SEQ_OP]	VERIFY_1(EARGS,SVAL_DTYPE);
[SLE_OP]	VERIFY_1(EARGS,SVAL_DTYPE);
[SGE_OP]	VERIFY_1(EARGS,SVAL_DTYPE);
[SNE_OP]	VERIFY_1(EARGS,SVAL_DTYPE);
[AND_OP]	VERIFY_1(EARGS,SVAL_DTYPE);
[OR_OP]		VERIFY_1(EARGS,SVAL_DTYPE);
[NOT_OP]	VERIFY_1(EARGS,SVAL_DTYPE);
[VMAGN_OP]	VERIFY_1(EARGS,V3ECT_DTYPE);
[VDOT_OP]	VERIFY_2(EARGS,V3ECT_DTYPE,V3ECT_DTYPE);
[SVMUL_OP]	VERIFY_2(EARGS,SVAL_DTYPE,V3ECT_DTYPE);
[VMAKE_OP]	VERIFY_3(EARGS,SVAL_DTYPE,SVAL_DTYPE,SVAL_DTYPE);
[VADD_OP]	VERIFY_2(EARGS,V3ECT_DTYPE,V3ECT_DTYPE);
[VSUB_OP]	VERIFY_2(EARGS,V3ECT_DTYPE,V3ECT_DTYPE);
[TVMUL_OP]	VERIFY_2(EARGS,TRANS_DTYPE,V3ECT_DTYPE);
[TVADD_OP]	VERIFY_2(EARGS,TRANS_DTYPE,V3ECT_DTYPE);
[TVSUB_OP]	VERIFY_2(EARGS,TRANS_DTYPE,V3ECT_DTYPE);
[RVMUL_OP]	VERIFY_2(EARGS,ROTN_DTYPE,V3ECT_DTYPE);
[RMAGN_OP]	VERIFY_1(EARGS,ROTN_DTYPE);
[AXIS_OP]	VERIFY_1(EARGS,ROTN_DTYPE);
[POS_OP]	VERIFY_1(EARGS,TRANS_DTYPE);
[ORIENT_OP]	VERIFY_1(EARGS,TRANS_DTYPE);
[RRMUL_OP]	VERIFY_2(EARGS,ROTN_DTYPE,ROTN_DTYPE);
[UVECT_OP]	VERIFY_1(EARGS,V3ECT_DTYPE);
[AXW_ROTN_OP]	VERIFY_2(EARGS,V3ECT_DTYPE,SVAL_DTYPE);
[FTOF_OP]	VERIFY_2(EARGS,FRAME_DTYPE,FRAME_DTYPE);
[TMAKE_OP]	VERIFY_2(EARGS,ROTN_DTYPE,V3ECT_DTYPE);
[TTMUL_OP]	VERIFY_2(EARGS,TRANS_DTYPE,TRANS_DTYPE);
[TINVRT_OP]	VERIFY_1(EARGS,TRANS_DTYPE);
[DEPR_OP]	VERIFY_1(EARGS,FRAME_DTYPE);
[FMAKE_OP]	VERIFY_2(EARGS,ROTN_DTYPE,V3ECT_DTYPE);

[LAST_OP]	END;

	END;
!  asgbki, identlookup, vblmake, vtry, mkblkbody;

RPTR(BLOCK) GVLBLK; ! Current block being gobbled;
RPTR(BLOCK) IDBLK; ! Block ident of last thing from identlookup;
RPTR(CMON) CCMON;  ! Current cmon being gobbled (if any);

INTEGER ALSOTYPE;  !  Used to tell the type of NEWV and OLDV in changers;
INTEGER UNIQUENO;INITIALIZE(UNIQUENO←0);
INTEGER BLKNO;INITIALIZE(BLKNO←0);

PROCEDURE ASGBKI(RPTR(BLOCK) B);
	BEGIN
	ITEMVAR DUMMY;
	INTEGER FLAG;
	DO	BEGIN
		BLKNO←BLKNO+1;
		DUMMY←CVSI("$B"&CVS(BLKNO),FLAG);
		IF FLAG THEN
			NEW_PNAME(BLOCK:BLID[B]←NEW(B),"$B"&CVS(BLKNO));
		END UNTIL FLAG;
	END;

RANY PROCEDURE IDENTLOOKUP(RPTR(IDENT) V);
	BEGIN 
	RANY ITEMVAR VID;
	IF RECTYPE(V)≠LOC(IDENT) THEN
		BEGIN
		USERERR(1,1,"DRYROT IN IDENTLOOKUP");
		RETURN(RNULL);
		END;
	IDBLK←GVLBLK;
	WHILE IDBLK≠NULL_RECORD DO
		BEGIN
		IF BLOCK:BLID[IDBLK]⊗IDENT:ID[V]≡BIND VID THEN
			RETURN(∂(VID));
		IDBLK←BLOCK:PARENT[IDBLK];
		END;
	RETURN(V);
	END;

PROCEDURE ENSYM(RPTR(IDENT) ID;RANY V;REFERENCE RANY ITEMVAR IDSLOT);
	BEGIN
	STRING IDSTR;
	IF IDSLOT=ANY THEN
		IDSLOT←NEW(V);
	IF RECTYPE(ID)≠LOC(IDENT) THEN
		BEGIN
                PRINT(CRLF&"****");RECPRN(ID);PRINT(CRLF);
		USERERR(1,1,"NEED AN ID HERE");
		END;
	IDENTLOOKUP(ID);
	IDSTR←ITMNAM(BLOCK:BLID[GVLBLK])&"."&ITMNAM(IDENT:ID[ID]);
	IF IDBLK=GVLBLK THEN
		BEGIN
		USERERR(1,1,"WARNING DUP ID: "&IDSTR);
		IDSTR←IDSTR&"."&CVS(UNIQUENO←UNIQUENO+1);
		END;
	NEW_PNAME(IDSLOT,IDSTR);
	MAKE BLOCK:BLID[GVLBLK]⊗IDENT:ID[ID]≡IDSLOT;
	END;

RPTR(VARIABLE,LBLVAR) PROCEDURE VBLMAKE(RPTR(IDENT) V;INTEGER DTYP);
	BEGIN
	RPTR(BLOCK) ITEMVAR BID;
	RPTR(IDENT) ITEMVAR VID;
	RPTR(VARIABLE,LBLVAR) ITEMVAR VVID;
	RPTR(VARIABLE,LBLVAR) VV;
	INTEGER C;
	IF DTYP=STMLAB_DTYPE∨DTYP=CHGLAB_DTYPE∨
	   DTYP=OMNLAB_DTYPE∨DTYP=CLCLAB_DTYPE THEN
		VV←NEW_LBL(VVID←NEW(RNULL),DTYP,GVLBLK)
	ELSE
		VV←NEW_VAR(VVID←NEW(RNULL),DTYP,GVLBLK);
	∂(VVID)←VV;
	ENSYM(V,VV,VARIABLE:NAME[VV]);
	RETURN(VV);
	END;
	

RPTR(VARIABLE,LBLVAR) PROCEDURE VTRY(RANY V; INTEGER DTYP (INVALID_DTYPE));
    BEGIN  "vtry" 
    ! Modified by RF.  Returns V.  If it was a declared variable, it
    checks its type to make sure it is DTYP (unless DTYP was not
    specified).  If it was not declared, VTRY declares it with DTYP.
    Complains if V is not a decllared variable or an IDENT.;

    RPTR(VARIABLE) VAR;
    INTEGER DUMMY;
    INTEGER RT,VDT;
    RT←RECTYPE(V);
    IF RT=LOC(IDENT) THEN
	BEGIN
	V←IDENTLOOKUP(V);
	RT←RECTYPE(V);
	END;
    IF RT = LOC(IDENT) THEN
    	BEGIN  ! May be declared;
        USERERR(1,1,"VTRY: Will define " & CVIS(IDENT:ID[V],DUMMY));
        VAR←VBLMAKE(V,DTYP);
        END
    ELSE IF RT = LOC(VARIABLE)
	THEN BEGIN  ! Just need to check the type;
	VAR←V;
	END
    ELSE IF RT = LOC(LBLVAR) THEN
	BEGIN
	RETURN(LBLVAR:SEMANTICS[V]);
	END
    ELSE BEGIN
	USERERR(1,1,"VTRY: Bad argument");
	RETURN(V);
	END;
    VDT←VARIABLE:DATATYPE[VAR];
    IF (DTYP ≠ INVALID_DTYPE) ∧ (VDT ≠ DTYP) THEN
    	BEGIN  ! May want to put right type in;
	IF VDT = INVALID_DTYPE 	THEN VARIABLE:DATATYPE[VAR] ← DTYP
	ELSE IF VDT = FRAME_DTYPE ∧ DTYP=TRANS_DTYPE THEN BEGIN ! OK; END
	ELSE USERERR(1,1,"VTRY: " & CVIS(VARIABLE:NAME[V],DUMMY) & 
            " has wrong type");
	END;
    RETURN(VAR);
    END "vtry";


PROCEDURE MKBLKBODY(REFERENCE RCELL C);
	BEGIN
	RPTR(BLKOP) BEN,BEX;
	BEN←NEW_RECORD(BLKOP);BLKOP:OP[BEN]←ENTERBLOCK;
	BEX←NEW_RECORD(BLKOP);BLKOP:OP[BEX]←LEAVEBLOCK;
	C←APPEND(C,CONS(STMAKE(BEX),NULL_RECORD));
	CONSON(STMAKE(BEN),C);
	END;
!  grovel (lllop, gllop, widget, stgrovel, lgrovel, constelim);

INTERNAL RANY RECPROC GROVEL(RANY SE);
	BEGIN
	RCELL C;
	RANY KIND,V;
	INTEGER IX;
	OWN INTEGER GLBFLG;  ! Used for global declarations;
	LABEL REGROVEL;
	RANY PROCEDURE LLLOP;
		RETURN(LLOP(C));

	RANY PROCEDURE GLLOP;
		IF C ≠ RNULL THEN RETURN(GROVEL(LLLOP)) ELSE RETURN(RNULL);

	ITEMVAR PROCEDURE WIDGET;	! world id get;
		BEGIN 
		RANY IC;
		IF C=NULL_RECORD THEN RETURN(ANY);
		IC←VTRY(LLLOP,WORLD_DTYPE);
		IF RECTYPE(IC)≠LOC(VARIABLE) THEN RETURN(ANY);
		IF VARIABLE:DATATYPE[IC]≠WORLD_DTYPE THEN
			BEGIN
                        PRINT(CRLF&"****");ALPRIN(IC);PRINT(CRLF);
			USERERR(1,1,"MUST HAVE A WORLD VARIABLE");
			RETURN(ANY);
			END;
		RETURN(VARIABLE:NAME[IC]);
		END;
		
	RSTMNT PROCEDURE STGROVEL;
		BEGIN
		IF C≠NULL_RECORD THEN
			RETURN(CHKREC(GLLOP,LOC(STMNT)))
		ELSE
			RETURN(STMAKE(NULL_RECORD));
			! RHT: 3-23-76 Used to return NULL_RECORD;
		END;

	RCELL RECPROC LGROVEL(RCELL C);
		BEGIN  !  Grovels down a list;
		RCELL C1,C2,C3;
		C1←C3←NULL_RECORD;
		WHILE C≠NULL_RECORD DO
			BEGIN
			C2 ← GROVEL(CELL:CAR[C]);
			IF C2 ≠ RNULL
			    THEN BEGIN  ! This case added by RF;
			    C2 ← CONS(C2,RNULL);
			    IF C1=NULL_RECORD
       			    THEN C1←C3←C2
			    ELSE CELL:CDR[C1] ← C2;
			    C1←C2;
			    END;
			C←CELL:CDR[C];
			END;
		RETURN(C3);
		END;
	
RPTR (VALU$,EXPRN) PROCEDURE CONSTELIM (RPTR(EXPRN) EX);
    BEGIN "constelim"  ! Coded by RF.  Takes the expression EX and
    replaces it with a simpler one if possible.  At the moment, only
    checks one level deep, since it is called repeatedly at each level.
    It should be simple to make it recursive;
    INTEGER TYP, FLAG;
    ITEMVAR DUMMY;
    RANY PTR;
    IF RECTYPE(EX) ≠ LOC(EXPRN)
    THEN BEGIN
            PRINT(CRLF&"****");ALPRIN(EX);
            USERERR(1,1,"CONSTELIM:  Not an expression");
            RETURN(EX);
            END;
    !  Make sure the operands are all constants;
    PTR ← EXPRN:ARGS[EX];
    WHILE PTR ≠ RNULL DO
        BEGIN "cloop"
        TYP ← RECTYPE(CELL:CAR[PTR]);
        IF FLAG ← (TYP=LOC(SVAL) ∨ TYP=LOC(V3ECT) ∨ TYP=LOC(ROTN) ∨ TYP=LOC(TRANS)
            ∨ TYP=LOC(FRAME))
        THEN PTR ← CELL:CDR[PTR]
        ELSE DONE "cloop";
        END "cloop";
    IF ¬FLAG THEN RETURN(EX)  !  Can't do anything;
    ELSE RETURN(EVALEXPR(EX,DUMMY));
    END;
!  grovel: REGROVEL:  DIR, EOP, DTYP;

REGROVEL:
	IF RECTYPE(SE)≠LOC(CELL) THEN
		BEGIN  ! Modified by RF so that VTRY includes CHKREC;
			! **** I don't see any call to CHKREC in VTRY ****;
		IF RECTYPE(SE) = LOC(IDENT) 
		THEN RETURN(VTRY(SE))
		ELSE RETURN(SE);
		END;
	KIND←CELL:CAR[SE];
	C←CELL:CDR[SE];
			
	IX←RECTYPE(KIND);
	IF IX=LOC(IDENT) THEN
		BEGIN
		KIND←IDENTLOOKUP(KIND);
		IX←RECTYPE(KIND);
		END;
	IF IX=LOC(LBLVAR) THEN
		BEGIN
		V←GROVEL(C);
		IX←RECTYPE(V);
                IF LBLVAR:SEMANTICS[KIND]≠NULL_RECORD THEN
			BEGIN
                        PRINT(CRLF&"****");ALPRIN(KIND);
                        USERERR(1,1,"DUPLICATE USE OF LABEL")
			END
                ELSE
			ASGLBL(KIND,V);
		RETURN(V);
		END
	ELSE IF IX≠LOC(RESERVED_WORD) THEN
		RETURN(LGROVEL(SE));

	IX←RESERVED_WORD:RWTYPE[KIND];

	CASE -IX OF
		BEGIN

[-DIR_CODE]	BEGIN
		CASE RESERVED_WORD:CODE[KIND] OF
			BEGIN

	[DSKIN_OP]	BEGIN
			V←GLLOP;
			IF RECTYPE(V)=LOC(STCONST) THEN
				BEGIN
				INTEGER CH;
				CH←READFILE(∂(STCONST:VAL[V]));
				IF CH<0 THEN
					RETURN(NULL_RECORD);
				INPLEV←INPLEV+1;
				SCNCHN[INPLEV]←CH;
				SCNSTK[INPLEV]←INPUT(SCNCHN[INPLEV],LINBRK);
				IF EQU(SCNSTK[INPLEV][1 FOR 9],"COMMENT ⊗") THEN
				BEGIN "skip over E directory page"
				    DO SCNSTK[INPLEV]←INPUT(SCNCHN[INPLEV],LINBRK)
				    UNTIL EQU(SCNSTK[INPLEV][1 FOR 3],"C⊗;")
					    ∨ EOF[SCNCHN[INPLEV]];
				    IF EOF[SCNCHN[INPLEV]] THEN
					USERERR(1,1,"DIRECTORY END NOT DETECTED");
				    SCNSTK[INPLEV]←NULL
				END;
				SE←READ;
				GO TO REGROVEL;
				END;
			END;

	[INIOUT_OP]	BEGIN
			INITIALIZE_OUTPUT;
			RETURN(NULL_RECORD);
			END;

	[0]		END;
		END;

[-EOP_CODE]	BEGIN "EOPCODE"
		V←NEW_RECORD(EXPRN);
		EXPRN:OP[V]←RESERVED_WORD:CODE[KIND];
		EXPRN:ARGS[V]←LGROVEL(C);
		DTYPE_CHECK(V);
		V ← CONSTELIM(V);
		RETURN(V);
		END;
		
[-DTYP_CODE]	BEGIN "VBL"
		IF RESERVED_WORD:CODE[KIND] = GVAL_DTYPE THEN
                    BEGIN "globdec"
                    GLBFLG ← TRUE;
                    LGROVEL(C);
                    GLBFLG ← FALSE;
                    END
		ELSE WHILE C≠NULL_RECORD DO
			BEGIN
                        V←LLLOP;  ! Modified by RF;
				  !  Further modified by RHT;
                        IF RECTYPE(V)≠LOC(IDENT) THEN
                                BEGIN
                                PRINT(CRLF&"****");RECPRN(V);PRINT(CRLF);
                                USERERR(1,1,"FUNNY THING FOR VARIABLE");
                                CONTINUE;
                                END;
                        V ← VBLMAKE(V,RESERVED_WORD:CODE[KIND]);
			IF GLBFLG THEN 
				VARIABLE:ATTRIBUTES[V] 
					← VARIABLE:ATTRIBUTES[V] LOR GLBAL;
                        END;
		RETURN(RNULL);  ! Used to return V.  Changed by RF;
		END;

!  grovel: main body:   PROG,BLOCK,COBLOCK,FORR,WHIL,IFF,PAUSE,ABORT,CIF,COMMNT;

[-RW_CODE]	BEGIN "RWCODE"
		CASE RESERVED_WORD:CODE[KIND] OF
			BEGIN

	[PROGTYPE]	BEGIN
			V←NEW_RECORD(PROG);
			PROG:CODE[V]←STGROVEL;
			RETURN(STMAKE(V));
			END;

	[BLOCKTYPE]	BEGIN  ! Modified by RF;
			RPTR(BLOCK) SAVEBLK;
			V←NEW_RECORD(BLOCK);
			ASGBKI(V);
			SAVEBLK←GVLBLK;
			BLOCK:PARENT[V]←SAVEBLK;
			GVLBLK←V;
			BLOCK:CODE[V] ← LGROVEL(C);
			! **** most likely only really want next if there
				are locals declared ****;
			MKBLKBODY(BLOCK:CODE[V]);
			GVLBLK←SAVEBLK;
			RETURN(STMAKE(V));
			END;

	[COBLOCKTYPE]	BEGIN
			V←NEW_RECORD(COBLOCK);
			COBLOCK:CODE[V]←LGROVEL(C);
			RETURN(STMAKE(V));
			END;

	[FORRTYPE]	BEGIN
			V←NEW_RECORD(FORR);
			FORR:CONVAR[V]←GLLOP;
			FORR:INITIAL[V]←GLLOP;
			FORR:STEP[V]←GLLOP;
			FORR:FINAL[V]←GLLOP;
			FORR:BODY[V]←STGROVEL;
			RETURN(STMAKE(V));
			END;

	[WHILTYPE]	BEGIN
			V←NEW_RECORD(WHIL);
			WHIL:COND[V]←GLLOP;
			WHIL:BODY[V]←STGROVEL;
			RETURN(STMAKE(V));
			END;

	[IFFTYPE]	BEGIN
			V←NEW_RECORD(IFF);
			IFF:COND[V]←GLLOP;
			IFF:THN[V]←STGROVEL;
			IFF:ELS[V]←STGROVEL;
			RETURN(STMAKE(V));
			END;

	[PAUSETYPE]	BEGIN
			V←NEW_RECORD(PAUSE);
			PAUSE:VAL[V]←GLLOP;
			RETURN(STMAKE(V));
			END;

	[ABORTTYPE]	BEGIN
			V←NEW_RECORD(ABORT);
			ABORT:VAL[V]←LGROVEL(C);  ! Gets a list of print items;
			RETURN(STMAKE(V));
			END;

	[CIFTYPE]	BEGIN
			V←NEW_RECORD(CIF);
			CIF:COND[V]←GLLOP;
			CIF:THN[V]←STGROVEL;
			CIF:ELS[V]←STGROVEL;
			RETURN(STMAKE(V));
			END;

	[COMMNTTYPE]	BEGIN  ! Coded by RF;
			V ← NEW_RECORD(COMMNT);
			!  COMMNT:HESAYS[V] ← LGROVEL(C);
			    ! You don't really want to keep that junk;
			RETURN(STMAKE(V));
			END;

!  grovel: main body:   NOMV, BINDV, DBD, NW, PVL, ASSERT, DENY, AFACT, SFACT;

	[NOMVTYPE]	BEGIN
			V←NEW_RECORD(NOMV);
			NOMV:E[V]←GLLOP;
			NOMV:WLD[V]←WIDGET;
			RETURN(V);
			END;

	[BINDVTYPE]	BEGIN
			V←NEW_RECORD(BINDV);
			BINDV:VAR[V]←GLLOP;
			RETURN(V);
			END;

	[DBDTYPE]	BEGIN
			V←NEW_RECORD(DBD);
			DBD:WLD[V]←WIDGET;
			RETURN(V);
			END;

	[NOTETYPE]	BEGIN
			V←NEW_RECORD(NOTE);
			NOTE:HESAYS[V]←GLLOP;	! Better be a string constant;
			RETURN(V);
			END;

	[NOTE1TYPE]	BEGIN
			V←NEW_RECORD(NOTE1);
			NOTE1:HESAYS[V]←GLLOP;	! Better be a string constant;
			RETURN(V);
			END;

	[NOTE2TYPE]	BEGIN
			V←NEW_RECORD(NOTE2);
			NOTE2:HESAYS[V]←GLLOP;	! Better be a string constant;
			RETURN(V);
			END;

	[NWTYPE]	BEGIN  ! Brave new world, that has such creatures;
			V←NEW_RECORD(NW);
			NW:WLD[V]←WIDGET;
			RETURN(STMAKE(V));
			END;

	[PVLTYPE]	BEGIN
			V←NEW_RECORD(PVL);
			PVL:VL[V]←LGROVEL(C);
			RETURN(V);
			END;

	[PASTYPE]	BEGIN			! Add by arg;
			RPTR(AFACT) VV;
			VV←NEW_RECORD(AFACT);
			AFACT:LEFT[VV]←GLLOP;
			AFACT:RIGHT[VV]←GLLOP;	! Note: afact:reln[vv]=0 ≡ "=";
			V←NEW_RECORD(ASSERT);
			ASSERT:FACT[V]←VV;
			ASSERT:WLD[V]←ANY;
			RETURN(STMAKE(V));
			END;

	[ASSERTTYPE]	BEGIN
			V←NEW_RECORD(ASSERT);
			ASSERT:FACT[V]←GLLOP;
			ASSERT:WLD[V]←WIDGET;
			RETURN(STMAKE(V));
			END;

	[DENYTYPE]	BEGIN
			V←NEW_RECORD(DENY);
			DENY:FACT[V]←GLLOP;
			DENY:WLD[V]←WIDGET;
			RETURN(STMAKE(V));
			END;

	[AFACTTYPE]	BEGIN
			V←NEW_RECORD(AFACT);
			AFACT:LEFT[V]←GLLOP;
			IX←CHAR_REC:CHAR[CHKREC(LLLOP,LOC(CHAR_REC))];
			AFACT:RELN[V]←STINDX("<≤=≥>",IX)-3;
			AFACT:RIGHT[V]←GLLOP;
			RETURN(V);
			END;

	[SFACTTYPE]	BEGIN
			V←NEW_RECORD(SFACT);
			SFACT:PATT[V]←LGROVEL(C);
			RETURN(V);
			END;

!  grovel: main body:   AFFIX, UNFIX, GASSIGN, CALCULATOR, CHANGER, ALSODO, SPECVAL;

	[AFFIXTYPE]	BEGIN
			V←NEW_RECORD(AFFIX);
			AFFIX:FRAME1[V] ← VTRY(LLLOP, FRAME_DTYPE);  !  Modif. by RF;
			AFFIX:FRAME2[V] ← VTRY(LLLOP, FRAME_DTYPE);  !  Modif. by RF;
			AFFIX:BYVAR[V] ← VTRY(LLLOP, TRANS_DTYPE);  ! Modif. by RF;
			AFFIX:ATEXP[V]←GLLOP;
			AFFIX:RIGID[V]←GLLOP;
			RETURN(STMAKE(V));
			END;

	[UNFIXTYPE]	BEGIN
			V←NEW_RECORD(UNFIX);
			UNFIX:FRAME1[V] ← VTRY(LLLOP, FRAME_DTYPE);
			UNFIX:FRAME2[V] ← VTRY(LLLOP, FRAME_DTYPE);
			RETURN(STMAKE(V));
			END;

	[GASSIGNTYPE]	BEGIN  ! Modified by RF;
			V←NEW_RECORD(GASSIGN);
			GASSIGN:VAR[V]←LLLOP;
			IX←CHAR_REC:CHAR[CHKREC(LLLOP,LOC(CHAR_REC))];
			GASSIGN:OP[V]←IF IX = "=" THEN 1
					ELSE IF IX = "≠" THEN 2 
					ELSE IF IX = "<" ∨ IX = "←" THEN 3
					ELSE 0;
			GASSIGN:CLC[V]←GLLOP;
			GASSIGN:VAR[V] ← 
			    VTRY(GASSIGN:VAR[V],GET_DTYPE(GASSIGN:CLC[V]));
			RETURN(STMAKE(V));
			END;

	[CALCULATORTYPE] BEGIN
			V←NEW_CALC(GLLOP);
			CONSON(V,BLOCK:CLCS[GVLBLK]);
			RETURN(V);
			END;

	[CHANGERTYPE]	BEGIN
			V←BLDCHG(NULL_RECORD,GVLBLK);
			CHANGER:CODE[V]←STGROVEL;
			RETURN(V);
			END;

	[ALSODOTYPE]	BEGIN 
			V←NEW_RECORD(ALSODO);
			ALSODO:VAR[V] ← VTRY(LLLOP);
			ALSOTYPE ← VARIABLE:DATATYPE[ALSODO:VAR[V]];
			ALSODO:OP[V] ← 1;
			ALSODO:CHG[V] ← NEW_RECORD(CHANGER);
			CHANGER:BLID[ALSODO:CHG[V]] ← GVLBLK;
			CHANGER:CODE[ALSODO:CHG[V]] ← GLLOP;
			CONSON(V,BLOCK:ALSOS[GVLBLK]);
			!  Doesn't handle the TRIGGERS or NAME fields;
			RETURN(STMAKE(V));
			END;

	[SPECVALTYPE]	BEGIN  
			EXTERNAL RVAR OLDV;  ! In HLAREC;
			V←NEW_RECORD(SPECVAL);
			IF VTRY(LLLOP) = OLDV
			THEN SPECVAL:OLD[V] ← TRUE
			ELSE SPECVAL:OLD[V] ← FALSE;
			RETURN(V);
			END;

!  grovel: main body:   V3ECT, TRANS, ASSIGNMENT, EVDO, PRNT;

	[V3ECTTYPE]	BEGIN
			V←NEW_RECORD(V3ECT);
			V3ECT:X[V]←SVAL:VAL[LLLOP];
			V3ECT:Y[V]←SVAL:VAL[LLLOP];
			V3ECT:Z[V]←SVAL:VAL[LLLOP];
			RETURN(V);
			END;

	[TRANSTYPE]	BEGIN
			V←NEW_RECORD(TRANS);
			TRANS:R[V]←GLLOP;
			TRANS:P[V]←GLLOP;
			RETURN(V);
			END;

	[PRNTTYPE]	BEGIN "prnt"
			V←NEW_RECORD(PRNT);
			PRNT:VAL[V] ← LGROVEL(C); ! Gets a list of print items;
			RETURN(STMAKE(V));
			END "prnt";

        [ASSIGNMENTTYPE] BEGIN  "assign" ! Modified by RF to check type consistency;
                        V←NEW_RECORD(ASSIGNMENT);
                        ASSIGNMENT:VAR[V] ← LLLOP;
	 		ASSIGNMENT:VAL[V] ← GLLOP;
			ASSIGNMENT:VAR[V] ← 
			    VTRY(ASSIGNMENT:VAR[V],GET_DTYPE(ASSIGNMENT:VAL[V]));
                        RETURN(STMAKE(V));
                        END "assign";

	[EVDOTYPE]	BEGIN 
			!  e.g.: (EV EVAR1 +) will signal the event;
			V ← NEW_RECORD(EVDO);
			EVDO:VAR[V] ← VTRY(LLLOP,EVENT_DTYPE);
			IX ← CHAR_REC:CHAR[CHKREC(LLLOP,LOC(CHAR_REC))];
			IF IX = "+"
                        THEN EVDO:OP[V] ← 0
                        ELSE IF IX = "-"
			THEN EVDO:OP[V] ← 1
			ELSE USERERR(1,1,"What kind of EV is " & IX & "?");
			RETURN(STMAKE(V));
			END;
			
	[CMABLETYPE]	BEGIN 
			!  e.g.: (CMABLE + cmon) will enable the cmon;
			V ← NEW_RECORD(CMABLE);
			IX ← CHAR_REC:CHAR[CHKREC(LLLOP,LOC(CHAR_REC))];
			IF IX = "+" THEN CMABLE:FLAG[V] ← 0
                        ELSE IF IX = "-" THEN CMABLE:FLAG[V] ← 1
			ELSE USERERR(1,1,"What kind of CMABLE is " & IX & "?");
				! Get the cmon's label;
			IF C≠RNULL THEN		! refers to labelled cmon;
			    CMABLE:WHAT[V] ← VTRY(LLLOP,OMNLAB_DTYPE)
			ELSE 			! refers to unlabelled cmon;
			    IF CCMON ≠ RNULL THEN CMABLE:WHAT[V] ← CCMON
			    ELSE USERERR(1,1,"Must specify name of cmon.");
			RETURN(STMAKE(V));
			END;
!  grovel: main body:   MOVE$, OPERATE, CENTER, STOP, motion clauses;

	[MOVE$TYPE]	BEGIN  "move$" ! Coded by RF;
			RANY P;
			V ← NEW_RECORD(MOVE$);
			MOVE$:WHAT[V] ← GLLOP; ! **** used to be LLLOP
						     with some comment about 
						     FRAME or SCALAR ****;
			MOVE$:DEST[V] ← GLLOP;
			MOVE$:DEXP[V] ← NEW_RECORD(DEXPR);
			    ! Can expect VIA, DURATION, CMON, DEPROACHES;
			MOVE$:CLAUSES[V] ← LGROVEL(C);
			P←MOVE$:CLAUSES[V];
			WHILE P ≠ RNULL DO	! All this does is turn CMON & S_FAC;
			    BEGIN		! statements into regular clauses;
			    IF RECTYPE(CELL:CAR[P])=LOC(STMNT) THEN
				CELL:CAR[P]←STMNT:SEMANTICS[CELL:CAR[P]];
			    P←CELL:CDR[P];
			    END;
			RETURN(STMAKE(V));
			END "move$";

	[OPERATETYPE]	BEGIN  "operate" ! Coded by RF;
			V ← NEW_RECORD(OPERATE);
			OPERATE:WHAT[V] ← GLLOP;
			OPERATE:DEST[V] ← GLLOP;
			OPERATE:DEXP[V] ← NEW_RECORD(DEXPR);
			    ! Can expect VIA, DURATION, CMON;
			OPERATE:CLAUSES[V] ← LGROVEL(C);
			RETURN(STMAKE(V));
			END "operate";

	[CENTERTYPE]	BEGIN  "center" ! Coded by RF;
			V ← NEW_RECORD(CENTER);
			CENTER:CF[V] ← GLLOP;
			    ! Can expect CMON;
			CENTER:CLAUSES[V] ← LGROVEL(C);
			RETURN(STMAKE(V));
			END "center";

	[STOPTYPE]	BEGIN "stop" ! Coded by RF;
			V ← NEW_RECORD(STOP);
			STOP:CF[V] ← GLLOP;
			RETURN(STMAKE(V));
			END "stop";

	[CMONTYPE]	BEGIN  ! Added by RF;
			RPTR(CMON) S;
			S ← CCMON;		! save outermost cmon;
			CCMON ← V ← NEW_RECORD(CMON);
			IX ← CHAR_REC:CHAR[CHKREC(LLLOP,LOC(CHAR_REC))];
			IF IX = "+" THEN CMON:FLAGS[V] ← 0	   ! Regular cmon;
			   ELSE IF IX = "-" THEN CMON:FLAGS[V] ← 1 ! Deferred cmon;
			   ELSE USERERR(1,1,"What kind of CMON is " & IX & "?");
			CMON:CONDITION[V] ← GLLOP;
			CMON:CONCLUSION[V] ← STGROVEL;
			CONSON(V,BLOCK:CMONS[GVLBLK]);
			CCMON ← S;		! restore old outermost cmon;
			RETURN(STMAKE(V));
			END;

	[VIATYPE]	BEGIN "via"  ! Coded by RF;
			RANY CLS;  ! Clause;
			V ← NEW_RECORD(VIA);
			VIA:PLACE[V] ← GLLOP;
			VERIFY_DTYPE(VIA:PLACE[V],TRANS_DTYPE); ! Check type is ok;
			VIA:ACTPLACE[V] ← NEW_RECORD(DEXPR);
			WHILE C ≠ RNULL DO
			    BEGIN
			    IF RECTYPE(CLS←GLLOP) = LOC(VELOCITY)
			    THEN VIA:VELOC[V] ← CLS
			    ELSE IF RECTYPE(CLS) = LOC(DURATION)
			    THEN VIA:TIME[V] ← CLS
			    ELSE IF RECTYPE(CLS) = LOC(STMNT)
			    THEN VIA:CODE[V] ← CLS
			    ELSE BEGIN ALPRIN(CLS);PRINT(CRLF);
				USERERR(1,1,"Funny thing for VIA clause") END;
			    END;
			RETURN(V);
			END "via";

	[ARRIVALTYPE]	BEGIN "arrival"	  ! coded by ARG;
			V ← NEW_RECORD(ARRIVAL);
			ARRIVAL:THRU[V] ← GLLOP;
			ARRIVAL:ACTPLACE[V] ← NEW_RECORD(DEXPR);
			RETURN(V);
			END "arrival";

	[DEPARTURETYPE]	BEGIN "departure"  ! coded by ARG;
			V ← NEW_RECORD(DEPARTURE);
			DEPARTURE:THRU[V] ← GLLOP;
			DEPARTURE:ACTPLACE[V] ← NEW_RECORD(DEXPR);
			RETURN(V);
			END "departure";

	[WOBBLETYPE]	BEGIN "wobble"  ! coded by ARG;
			V ← NEW_RECORD(WOBBLE);
			WOBBLE:VAL[V] ← GLLOP;
			RETURN(V);
			END "wobble";

	[OPENINGTYPE]	BEGIN "opening"   ! coded by ARG;
			V ← NEW_RECORD(OPENING);
			OPENING:VAL[V] ← GLLOP;
			RETURN(V);
			END "opening";

	[DURATIONTYPE]	BEGIN "duration"  ! Coded by RF;
			V ← NEW_RECORD(DURATION);
			IX ← CHAR_REC:CHAR[CHKREC(LLLOP,LOC(CHAR_REC))];
			DURATION:TIME_RELN[V] ←
			    IF IX = ">" THEN 1
			    ELSE IF IX = "<" THEN 2
			    ELSE IF IX = "=" THEN 3
			    ELSE 0;
			DURATION:TIME[V] ← GLLOP;
			RETURN(V);
			END "duration";

	[VELOCITYTYPE]	BEGIN "velocity" ! coded by ARG;
			V ← NEW_RECORD(VELOCITY);
			VELOCITY:VELOC[V] ← GLLOP;
			RETURN(V);
			END "velocity";

	[FORCETYPE]	BEGIN "force"  ! Coded by ARG 5-1-77;
			V ← NEW_RECORD(FORCE);
			FORCE:DIRECT[V] ← GLLOP;
			IX ← CHAR_REC:CHAR[CHKREC(LLLOP,LOC(CHAR_REC))];
			FORCE:REL[V] ← IF IX = "<" THEN SIGLT ELSE SIGGE;
				! treat "=" & "≥" the same;
			FORCE:VAL[V] ← GLLOP;
			IX ← CHAR_REC:CHAR[CHKREC(LLLOP,LOC(CHAR_REC))];
			FORCE:TYPE[V] ← IF IX = "-" THEN FALSE ELSE TRUE;
				! force along axis = TRUE, torque about axis = FALSE;
			FORCE:F_F[V] ← GLLOP; ! Get force frame spec;
			RETURN(V);
			END "force";

	[F_FRAMETYPE]	BEGIN "force frame"
			V ← NEW_RECORD(F_FRAME);
			F_FRAME:FRAME[V] ← GLLOP;
			IX ← CHAR_REC:CHAR[CHKREC(LLLOP,LOC(CHAR_REC))];
			F_FRAME:C_SYS[V] ← IF IX = "⊗" THEN FHAND ELSE FTABLE;
			RETURN(V);
			END "force frame";

	[S_FACTYPE]	BEGIN "speed_factor"  ! coded by ARG;
			V ← NEW_RECORD(S_FAC);
			S_FAC:VAL[V] ← GLLOP;
			RETURN(V);
			END "speed_factor";

	[0]		RETURN(NULL_RECORD)

			END;

		END;

[0]		END;

	RETURN(SE);
	END;


! MAIN PROGRAM;
IFCR FALSE THENC

WHILE TRUE DO
	BEGIN "REP"
	EXTERNAL PROCEDURE BAIL;
	RANY R;
	BAIL;
	PRINT(CRLF);
	R←READ;
	ALPRIN(GROVEL(R));
	PRINT(CRLF);
	END;
ENDC

END $$PRGID;